home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
cpp_libs
/
intrvews
/
xgrab.lha
/
xgrab
/
grabst
/
delete.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-03-06
|
16KB
|
679 lines
/**
GRAB Graph Layout and Browser System
Copyright (c) 1986, 1988 Regents of the University of California
Copyright (c) 1989, Tera Computer Company
**/
/**
delete.c -- routines to add and delete parts of the digraph data structure
**/
#include "malloc.h"
#include "attribute.h"
#include "digraph.h"
#include "debug.h"
OUTEDGE *get_edge();
NODE *get_prev_node(), *get_next_node();
NODE *prev_dummy(), *next_dummy();
LEVEL *find_level();
char **dispose_out_edge();
short hash();
DeleteEdge();
DeleteNode(digraph, node)
DIGRAPH *digraph;
NODE *node;
/**
DeleteNode removes a node from the digraph structure.
First it removes associated in and out edges. Then it fixes up the
successor sets of its predecessors, and the predecessor sets of its
successors, deleting any associating dummy nodes along the way.
Finally, it releases the space used by the node.
**/
{
NODE *next_node, *prev_node, *decomp;
VNO vno, prev_vno, next_vno;
OUTEDGE *out_edge;
INEDGE *in_edge;
/**
Delete the associated in and out edges.
If its a dummy node, we must delete the edges between the previous
non-dummy node and the next non-dummy node.
**/
if (Is_dummy(node))
{
int i;
prev_node = get_prev_node(digraph, node);
next_node = get_next_node(digraph, node);
for (i = max_edges(prev_node, next_node); i > 0; i++)
{
if (get_edge(digraph, prev_node, next_node, i) != NULL)
{
dispose_edge(digraph, prev_node, next_node, i);
}
}
}
else if (Coalescer(node))
{
delete_coalescer_in_out(digraph, node);
}
else
/**
Fix up in-edge lists of nodes on out-edge list and out-edge lists
of nodes on in-edge list.
Note: if you can delete coalesced members without deleting the
coalescer, this won't work, because it doesn't take into account
the links to/from coalescer nodes which this node might be
a member of. But currently you can't do that.
**/
{
all_out_edges(node, out_edge)
loop
dispose_edge(digraph, node, Node(digraph, To_vno(out_edge)),
Ord(out_edge));
endloop
all_in_edges(node, in_edge)
loop
dispose_edge(digraph, Node(digraph, From_vno(in_edge)), node,
Ord(in_edge));
endloop
}
/**
Fix up successor sets of predecessors, remove predecessor dummy nodes.
Fix up predecessor sets of successors, remove successor dummy nodes.
**/
each_element(Ante_set(node), prev_vno)
loop
remove_ante_links(digraph, node, Node(digraph, prev_vno));
endloop
each_element(Succ_set(node), next_vno)
loop
remove_succ_links(digraph, node, Node(digraph, next_vno));
endloop
/* Unlink node from level structure, remove its vertex, free up space. */
dispose_node(digraph, node);
} /* DeleteNode */
delete_coalescer_in_out(digraph, node)
DIGRAPH *digraph;
NODE *node;
/**
recursively delete all in and out edges of the elements of
a coalescer node
**/
{
NODE *decomp;
VNO vno;
OUTEDGE *out_edge;
INEDGE *in_edge;
each_element(Expansion(node), vno)
loop
decomp = Node(digraph, vno);
if (Coalescer(decomp))
/* then recurse */
{
delete_coalescer_in_out(digraph, decomp);
}
else
{
all_out_edges(decomp, out_edge)
loop
dispose_edge(digraph, decomp, Node(digraph, To_vno(out_edge)),
Ord(out_edge));
endloop
all_in_edges(decomp, in_edge)
loop
dispose_edge(digraph, Node(digraph, From_vno(in_edge)), decomp,
Ord(in_edge));
endloop
}
endloop
}
DeleteEdge(digraph, from_node, to_node, ord)
DIGRAPH *digraph;
NODE *from_node, *to_node;
int ord;
/**
DeleteEdge deletes the edge from from_node to to_node. If there is only
one edge from from_node to to_node, it also deletes intervening dummy
nodes and the associated links.
**/
{
NODE *prev_node, *next_node;
VNO next_vno;
if (num_edges(from_node, to_node) == 1)
{
/**
There is only one edge. Delete intervening dummy nodes and
associated links.
First, search for the successor to from_node that goes to
to_node. Note that if there are no intervening dummy nodes,
this loop changes nothing, which is just fine.
**/
each_element(Succ_set(from_node), next_vno)
loop
next_node = Node(digraph, next_vno);
if (Is_dummy(next_node)
&& get_next_node(digraph, next_node) == to_node)
/* found the right dummy */
{
remove_link(from_node, next_node);
do
{
prev_node = next_node;
next_node = next_dummy(digraph, next_node);
remove_link(prev_node, next_node);
dispose_node(digraph, prev_node);
} while (Is_dummy(next_node));
break;
}
endloop;
remove_link(from_node, to_node);
}
dispose_edge(digraph, from_node, to_node, ord);
} /* DeleteEdge */
dispose_node(digraph, node)
DIGRAPH *digraph;
NODE *node;
/**
dispose_node removes the sets and attributes pointed to by node, removes
the associated vertex, unlinks the node from the level structure,
and frees up the space occupied by the node.
If node is a coalescer, it first recursively calls itself on all the
elements of the node.
**/
{
VNO vno;
if (Coalescer(node))
{
/* dispose of all members of a coalescer recursively */
each_element(Expansion(node), vno)
loop
dispose_node(digraph, Node(digraph, vno));
endloop
}
vno = Vno(node);
remove_from_level(digraph, node);
dispose(Ante_set(node));
dispose(Succ_set(node));
dispose(Expansion(node));
dispose_attr(node->attributes, NNodeAttr(digraph));
dispose_vertex(digraph, Name(node));
dispose(node);
Node(digraph, vno) = NULL;
} /* dispose_node */
dispose_attr(attr, num)
char **attr;
int num;
/* dispose of an array of character pointers. */
{
int i;
for (i = 0; i < num; i++)
{
dispose(attr[i]);
}
dispose(attr);
}
dispose_vertex(digraph, name)
DIGRAPH *digraph;
char *name;
/**
dispose_vertex locates the vertex identified by name and deletes it,
fixing up the pointer from the previous vertex.
**/
{
short hashcode;
VERTEX *vertex, *prev; /* used to chase down the vertex chain */
hashcode = hash(name);
vertex = digraph->hashtbl[hashcode];
if (strcmp(vertex->name, name) == 0) /* vertex is first in list */
{
digraph->hashtbl[hashcode] = vertex->next;
dispose(vertex->name);
dispose(vertex);
return;
}
/* search through list until name found */
vertex = digraph->hashtbl[hashcode];
while (vertex != NULL && (strcmp(vertex->name, name) != 0))
{
prev = vertex;
vertex = vertex->next;
}
if (vertex != NULL) /* found it */
{
prev->next = vertex->next;
dispose(vertex->name);
dispose(vertex);
return;
}
PrintError("dispose_vertex: name not found");
} /* dispose_vertex */
dispose_edge(digraph, from_node, to_node, ord)
DIGRAPH *digraph;
NODE *from_node, *to_node;
int ord;
/**
dispose_edge removes the edge with ordinality ord from the out_edge list
of from_node and from the in_edge list of to_node. If either node is
a dummy node, return, since dummy nodes have no edge lists. Coalescer
nodes have no edge lists, but their component nodes do, so fix up edge
lists of the component nodes recursively.
**/
{
VNO from_vno, to_vno;
NODE *from, *to;
char **attr; /* user-defined attributes of edge being deleted */
BRUSH db;
COLOR dc;
int max;
from_vno = Vno(from_node);
to_vno = Vno(to_node);
if (Is_dummy(from_node) || Is_dummy(to_node))
{
return;
}
if (!Coalescer(from_node) && !Coalescer(to_node))
{
attr = dispose_out_edge(from_node, to_vno, ord, &db, &dc);
dispose_attr(attr, NEdgeAttr(digraph));
dispose_in_edge(to_node, from_vno, ord);
return;
}
else if (Coalescer(from_node))
{
/**
ordinality for edges from a coalescer node is figured
by adding the ordinality of the edge to the sum of the
maximum ordinalities of the preceding nodes. So, if
a coalescer has 3 elements, A, B, and C, and we're looking
at the edges to D, of which A has 2, B has 1, and C has 2,
the ordinalities of the edges will be:
A: 1-2
B: 3
C: 4-5
assuming Vno(A) < Vno(B) < Vno(C).
**/
each_element(Expansion(from_node), from_vno)
loop
from = Node(digraph, from_vno);
if (ord <= (max = max_edges(from, to_node)))
{
dispose_edge(digraph, from, to_node, ord);
break;
}
else
{
ord -= max;
}
endloop
return;
}
else if (Coalescer(to_node))
{
each_element(Expansion(to_node), to_vno)
loop
to = Node(digraph, to_vno);
if (ord <= (max = max_edges(from_node, to)))
{
dispose_edge(digraph, from_node, to, ord);
break;
}
else
{
ord -= max;
}
endloop
return;
}
} /* dispose_edge */
char **dispose_out_edge(node, vno, ord, pb, pc)
NODE *node;
VNO vno;
int ord;
BRUSH *pb;
COLOR *pc;
/**
dispose of the edge from node to vno of ordinality ord.
Just chase down the outedge list until you find a match.
Set the values for the brush and color, and return the attributes.
**/
{
OUTEDGE *edge, *first_edge, *prev_edge;
char **attr; /* edge attributes */
/* check if it's the first outedge */
if (To_vno(node->out_edges) == vno && Ord(node->out_edges) == ord)
{
first_edge = node->out_edges;
node->out_edges = first_edge->next;
attr = first_edge->attributes;
*pb = Brush(first_edge);
*pc = Color(first_edge);
dispose(first_edge);
return (attr);
}
prev_edge = NULL; /* dummy value, for first pass */
/* now check the rest of the list */
all_out_edges(node, edge)
loop
if (To_vno(edge) == vno && Ord(edge) == ord)
{
prev_edge->next = edge->next;
attr = edge->attributes;
*pb = Brush(edge);
*pc = Color(edge);
dispose(edge);
return (attr);
}
prev_edge = edge;
endloop
if (debug)
{
printf("dispose_out_edge: edge not found\n");
}
return (NULL);
} /* dispose_out_edge */
dispose_in_edge(node, vno, ord)
NODE *node;
VNO vno;
int ord;
/**
dispose of the inedge from node to vno with ordinality ord.
Just chase down the inedge list until you find a match.
**/
{
INEDGE *edge, *first_edge, *prev_edge;
/* check the first inedge */
if (From_vno(node->in_edges) == vno && Ord(node->in_edges) == ord)
{
first_edge = node->in_edges;
node->in_edges = first_edge->next;
dispose(first_edge);
return;
}
prev_edge = NULL; /* dummy value, for first pass */
/* check the other inedges */
all_in_edges(node, edge)
loop
if (From_vno(edge) == vno && Ord(edge) == ord)
{
prev_edge->next = edge->next;
dispose(edge);
return;
}
prev_edge = edge;
endloop
if (debug)
{
printf("dispose_in_edge: edge not found\n");
}
} /* dispose_in_edge */
remove_ante_links(digraph, node, prev_node)
DIGRAPH *digraph;
NODE *node, *prev_node;
/**
remove_ante_links follows the chain of ancestor edges from node through
prev through the prev non-dummy node, deleting all edges and dummy
nodes along the way.
**/
{
NODE *curr, *prev;
remove_link(prev_node, node);
curr = prev_node;
while (Is_dummy(curr))
{
prev = prev_dummy(digraph, curr);
remove_link(prev, curr);
dispose_node(digraph, curr);
curr = prev;
}
} /* remove_ante_links */
remove_succ_links(digraph, node, next_node)
DIGRAPH *digraph;
NODE *node, *next_node;
/**
remove_succ_links follows the chain of successor edges from node through
next through the next non-dummy node, deleting all edges and dummy
nodes along the way.
**/
{
NODE *curr, *next;
remove_link(node, next_node);
curr = next_node;
while (Is_dummy(curr))
{
next = next_dummy(digraph, curr);
remove_link(curr, next);
dispose_node(digraph, curr);
curr = next;
}
} /* remove_succ_links */
remove_link(from_node, to_node)
NODE *from_node, *to_node;
/**
remove_link removes an edge between two nodes by removing the
appropriate elements from their successor and ancestor sets.
Recursively works for coalescer nodes, too.
**/
{
VNO vno;
if (Coalescer(from_node))
{
each_element(Expansion(from_node), vno)
loop
remove_link(Node(digraph, vno), to_node);
endloop;
}
if (Coalescer(to_node))
{
each_element(Expansion(to_node), vno)
loop
remove_link(from_node, Node(digraph, vno));
endloop;
}
remove_element(Succ_set(from_node), Vno(to_node));
remove_element(Ante_set(to_node), Vno(from_node));
} /* remove_link */
NODE *get_prev_node(digraph, node)
DIGRAPH *digraph;
NODE *node;
/**
get_prev_node returns a pointer to the previous non-dummy node, working
back from (dummy node) node.
**/
{
NODE *prev_node;
if ((prev_node = prev_dummy(digraph, node)) == NULL)
{
return NULL;
}
while (Is_dummy(prev_node))
{
if ((prev_node = prev_dummy(digraph, prev_node)) == NULL)
{
return NULL;
}
}
return (prev_node);
} /* get_prev_node */
NODE *get_next_node(digraph, node)
DIGRAPH *digraph;
NODE *node;
/**
get_next_node returns a pointer to the next non-dummy node, working
forward from (dummy node) node.
**/
{
NODE *next_node;
if ((next_node = next_dummy(digraph, node)) == NULL)
{
return NULL;
}
while (Is_dummy(next_node))
{
if ((next_node = next_dummy(digraph, next_node)) == NULL)
{
return NULL;
}
}
return (next_node);
} /* get_next_node */
remove_from_level(digraph, node)
DIGRAPH *digraph;
NODE *node;
/**
remove_from_level unlinks a node from a level and fixes the pointers
from/to the previous and next node on the level.
**/
{
LEVEL *level;
level = find_level(digraph, Vno(node));
if (level == NULL)
{
return;
}
if (Prev_member(node) != NULL)
{
Next_member(Prev_member(node)) = Next_member(node);
if (Next_member(node) != NULL)
Prev_member(Next_member(node)) = Prev_member(node);
}
else /* Prev_member(node) is NULL */
{
Order(level) = Next_member(node);
if (Next_member(node) != NULL)
Prev_member(Next_member(node)) = NULL;
}
remove_element(Members(level), Vno(node));
} /* remove_from_level */
dispose_digraph(digraph)
DIGRAPH *digraph;
/**
dispose_digraph steps through a digraph structure and frees up
all the space.
**/
{
NODE *node;
OUTEDGE *out_edge;
INEDGE *in_edge;
LEVEL *level;
if (digraph == NULL)
{
return;
}
dispose_attr(digraph->node_att_names, NNodeAttr(digraph));
dispose_attr(digraph->edge_att_names, NEdgeAttr(digraph));
all_nodes(digraph, node)
loop
dispose(Ante_set(node));
dispose(Succ_set(node));
dispose(Expansion(node));
dispose(Name(node));
dispose(Text(node));
dispose(node->vertex);
all_out_edges(node, out_edge)
loop
dispose_attr(out_edge->attributes, NEdgeAttr(digraph));
dispose(out_edge);
endloop
all_in_edges(node, in_edge)
loop
dispose(in_edge);
endloop
dispose(node);
endloop
each_level(digraph, level)
loop
dispose(Members(level));
dispose(level);
endloop
dispose(Title(digraph));
dispose (digraph);
} /* dispose_digraph */